package org.summerframework.component.security.core.interceptor;

import org.summerframework.component.security.annotion.UserPermission;
import org.summerframework.core.base.result.DefaultResultCode;
import org.summerframework.core.exception.WebException;
import org.summerframework.core.util.ConvertUtils;
import org.summerframework.core.util.SpringContextUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.MethodUtils;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.method.HandlerMethod;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 用户是否有操作权限
 * <p>
 * 单用户权限使用配合{@link UserPermission}
 *
 * @author 石超
 * @version v1.0.0
 */
public class CheckUserPermissionInterceptor extends AbstractContextHandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }

        HandlerMethod handlerMethod = (HandlerMethod) handler;

        UserPermission userPermission = findAnnotation(handlerMethod, UserPermission.class);

        if (userPermission != null) {
            try {
                //获取service
                Object objectService = SpringContextUtil.getBean(userPermission.service());

                List<List<Object>> list = new ArrayList<>();

                Arrays.stream(userPermission.param()).forEachOrdered(key -> {
                    try {
                        String[] strings = ServletRequestUtils.getRequiredStringParameters(request, key);
                        boolean isStart = list.size() == 0;

                        for (int i = 0; i < strings.length; i++) {
                            List<Object> objects;

                            if (isStart) {
                                objects = new ArrayList<>();
                                list.add(objects);
                            } else {
                                objects = list.get(i);
                            }

                            objects.add(strings[i]);
                        }
                    } catch (ServletRequestBindingException e) {
                        throw new WebException(DefaultResultCode.ILLEGAL_ARGUMENT);
                    }
                });

                for (List<Object> objects : list) {
                    //调用service中的方法
                    Object object = MethodUtils.invokeExactMethod(objectService, userPermission.methodName(), convert(objects, userPermission.paramType()), userPermission.paramType());

                    //获取userId
                    if (object != null) {
                        Long userId;

                        if (StringUtils.isNotBlank(userPermission.property())) {
                            userId = Long.valueOf(BeanMap.create(object).get(userPermission.property()).toString());
                        } else {
                            userId = Long.valueOf(object.toString());
                        }

                        //判断是否一致, 不一致提示权限不足
                        if (!userId.equals(getContext().getLoginData().getUserId())) {
                            throw new WebException(DefaultResultCode.NOT_ALLOWED_OPERATION);
                        }
                    } else {
                        throw new WebException(DefaultResultCode.ILLEGAL_ARGUMENT);
                    }
                }
            } catch (WebException e) {
                throw e;
            } catch (Exception e) {
                throw new WebException(DefaultResultCode.SYSTEM_ERROR, e);
            }
        }

        return true;
    }

    private Object[] convert(List<Object> list, Class[] classes) {
        List<Object> returns = new ArrayList<>();
        if (list.size() != classes.length) {
            throw new WebException(DefaultResultCode.SYSTEM_ERROR);
        }

        for (int i = 0; i < classes.length; i++) {
            returns.add(ConvertUtils.copyProperties(list.get(i), classes[i]));
        }

        return returns.toArray();
    }
}
